@file:JvmMultifileClass
@file:JvmName("ViewKsl")

package hos.ksl

import android.app.Activity
import android.content.res.Resources
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.drawable.GradientDrawable
import android.os.SystemClock
import android.view.View
import android.view.ViewGroup
import android.view.Window
import androidx.annotation.ColorInt
import androidx.fragment.app.Fragment
import java.util.ArrayDeque
import java.util.concurrent.TimeUnit

/**
 * <p>Title: ViewKSL </p>
 * <p>Description:  </p>
 * <p>Company: www.mapuni.com </p>
 *
 * @author : 蔡俊峰
 * @date : 2024-05-09 17:30
 * @version : 1.0
 */

/**
 * Value of dp to value of px.
 *
 * @param dpValue The value of dp.
 * @return value of px
 */
fun dp2px(dpValue: Float): Int {
    val scale = Resources.getSystem().displayMetrics.density
    return (dpValue * scale + 0.5f).toInt()
}

inline fun <T : View> View.find(id: Int, viewJob: T.() -> Unit) {
    val view = findViewById<T>(id)
    view.viewJob()
}

inline fun <T : View> Activity.find(id: Int, viewJob: T.() -> Unit) {
    val view = findViewById<T>(id)
    view.viewJob()
}

inline fun <T : View> Fragment.find(id: Int, viewJob: T.() -> Unit) {
    view?.find<T>(id, viewJob)
}

inline fun <T : View> Window.find(id: Int, viewJob: T.() -> Unit) {
    val view = findViewById<T>(id)
    view.viewJob()
}

@Suppress("UNCHECKED_CAST")
inline fun <T : View> View.click(crossinline click: T.() -> Unit) {
    setOnClickListener {
        click.invoke(it as T)
    }
}

inline fun View.clickView(crossinline click: View.() -> Unit) {
    setOnClickListener {
        click.invoke(it)
    }
}

@Suppress("UNCHECKED_CAST")
inline fun <T : View> View.clickLong(crossinline click: T.() -> Boolean) {
    setOnLongClickListener {
        click.invoke(it as T)
    }
}

inline fun View.clickViewLong(crossinline click: View.() -> Boolean) {
    setOnLongClickListener {
        click.invoke(it)
    }
}


/**
 * 点击事件防抖动
 * @param interval 间隔时间, 如果为500表示500毫秒内只允许触发一次点击事件
 * @param unit 时间单位
 */
internal fun View.clickThrottle(
    interval: Long = 500,
    unit: TimeUnit = TimeUnit.MILLISECONDS,
    block: View.() -> Unit
) {
    setOnClickListener(ThrottleClickListener(interval, unit, block))
}

internal class ThrottleClickListener(
    private val interval: Long = 500,
    private val unit: TimeUnit = TimeUnit.MILLISECONDS,
    private var block: View.() -> Unit
) : View.OnClickListener {

    private var lastTime: Long = 0

    override fun onClick(v: View) {
        val currentTime = SystemClock.elapsedRealtime()
        if (currentTime - lastTime > unit.toMillis(interval)) {
            lastTime = currentTime
            block(v)
        }
    }
}

inline fun View.gradient(
    @ColorInt color: Int = Color.WHITE,
    radius: Float = dp2px(4f).toFloat(),
    horizontal: Int = dp2px(12f),
    vertical: Int = dp2px(8f),
    drawable: GradientDrawable .() -> Unit = {},
): View {
    with(GradientDrawable()) {
        setColor(color)
        radiusAll(radius)
        paddingHV(horizontal, vertical)
        //默认样式
        drawable()
        background = this
    }
    return this
}

@JvmOverloads
fun View.padding(
    left: Int = 0, top: Int = 0, right: Int = 0, bottom: Int = 0
): View {
    setPadding(left, top, right, bottom)
    return this
}

@JvmOverloads
fun View.paddingHV(
    horizontal: Int = 0,
    vertical: Int = 0
): View {
    setPadding(horizontal, vertical, horizontal, vertical)
    return this
}

@JvmOverloads
fun View.paddingAll(
    horizontal: Int = 0,
    vertical: Int = 0
): View {
    setPadding(horizontal, vertical, horizontal, vertical)
    return this
}

fun View.bitmap(): Bitmap {
    val measuredWidth = measuredWidth
    val measuredHeight = measuredHeight
    if (measuredWidth == 0 || measuredHeight == 0) {
        throw RuntimeException("调用该方法时，请确保View已经测量完毕，如果宽高为0，则抛出异常以提醒！")
    }
    val screenshot = Bitmap.createBitmap(measuredWidth, measuredHeight, Bitmap.Config.ARGB_8888)
    val canvas = Canvas(screenshot)
    val background = background
    if (background != null) {
        background.setBounds(0, 0, width, measuredHeight)
        background.draw(canvas)
    } else {
        canvas.drawColor(Color.WHITE)
    }
    draw(canvas) // 将 view 画到画布上
    return screenshot
}

fun <T> ViewGroup?.findTypeView(clazz: Class<T>): T? {
    if (this == null){
        return null
    }
    val deque = ArrayDeque<View>()
    deque.add(this)
    while (!deque.isEmpty()) {
        val node = deque.removeFirst()
        if (clazz.isInstance(node)) {
            return clazz.cast(node)
        } else if (node is ViewGroup) {
            var i = 0
            val count = node.childCount
            while (i < count) {
                deque.add(node.getChildAt(i))
                i++
            }
        }
    }
    return null
}
